1 Introduction

In this report, I will explore the red wine dataset. First, I will look at each individual attribute of this dataset and plot its distribution. Second, I will look at two attributes at a time to explore 1) how each input attribute is related to the output attribute–quality; 2) interesting pairs of input attributes. Third, I will examine three attributes by adding one additional attribute to some of the interesting two-attribute pairs. Finally, I will summarize the successes and problems I encounter during the data exploration process.

# Load all of the packages in this code chunk.
library(ggplot2)
library(corrplot)
library(RColorBrewer)
library(memisc)
# Load all of the packages in this code chunk.
library(ggplot2)
library(corrplot)
library(RColorBrewer)
library(memisc)

2 Univariate Exploration

In this section, I will first look at the structure of the data set. Then I will examine the distribution of each attribute individually by plotting its distribution.

dim(wine_reds)
# Convert quality into ordered categorical variable
wine_reds$quality <- ordered(wine_reds$quality)
str(wine_reds)
summary(wine_reds)

The red wine dataset contains 12 variables–11 input numerical variables based on physicochemical tests and 1 categorical output variable (quality) based on sensory data, with 1599 observations.

# Load the Data
wine_reds = read.csv('wineQualityReds.csv', row.names = 1)

2.1 Quality

dim(wine_reds)
[1] 1599   12

Out of the possible quality scores between 0 and 10, all of our red wines’ quality scores fall between 3 and 8. The dataset is not well balanced. Majority of red wines have a quality score of either 5 or 6. I am curious about what attributes make a wine earn a low quality score (quality = 3) or a high quality score (quality = 8).

2.2 Fixed Acidity

Most acids involved with wine are fixed or nonvolatile (do not evaporate readily).

# Convert quality into ordered categorical variable
wine_reds$quality <- ordered(wine_reds$quality)
str(wine_reds)
'data.frame':   1599 obs. of  12 variables:
 $ fixed.acidity       : num  7.4 7.8 7.8 11.2 7.4 7.4 7.9 7.3 7.8 7.5 ...
 $ volatile.acidity    : num  0.7 0.88 0.76 0.28 0.7 0.66 0.6 0.65 0.58 0.5 ...
 $ citric.acid         : num  0 0 0.04 0.56 0 0 0.06 0 0.02 0.36 ...
 $ residual.sugar      : num  1.9 2.6 2.3 1.9 1.9 1.8 1.6 1.2 2 6.1 ...
 $ chlorides           : num  0.076 0.098 0.092 0.075 0.076 0.075 0.069 0.065 0.073 0.071 ...
 $ free.sulfur.dioxide : num  11 25 15 17 11 13 15 15 9 17 ...
 $ total.sulfur.dioxide: num  34 67 54 60 34 40 59 21 18 102 ...
 $ density             : num  0.998 0.997 0.997 0.998 0.998 ...
 $ pH                  : num  3.51 3.2 3.26 3.16 3.51 3.51 3.3 3.39 3.36 3.35 ...
 $ sulphates           : num  0.56 0.68 0.65 0.58 0.56 0.56 0.46 0.47 0.57 0.8 ...
 $ alcohol             : num  9.4 9.8 9.8 9.8 9.4 9.4 9.4 10 9.5 10.5 ...
 $ quality             : Ord.factor w/ 6 levels "3"<"4"<"5"<"6"<..: 3 3 3 4 3 3 3 5 5 3 ...

Fixed acidity values range between 4 and 16, with most values range between 7 and 9. The distribution is slightly positively skewed. Transforming the x-axis into log scale can make it more normally distributed.

2.3 Volatile Acidity

The amount of acetic acid in wine, which at too high of levels can lead to an unpleasant, vinegar taste.

summary(wine_reds)
 fixed.acidity   volatile.acidity  citric.acid    residual.sugar     chlorides      
 Min.   : 4.60   Min.   :0.1200   Min.   :0.000   Min.   : 0.900   Min.   :0.01200  
 1st Qu.: 7.10   1st Qu.:0.3900   1st Qu.:0.090   1st Qu.: 1.900   1st Qu.:0.07000  
 Median : 7.90   Median :0.5200   Median :0.260   Median : 2.200   Median :0.07900  
 Mean   : 8.32   Mean   :0.5278   Mean   :0.271   Mean   : 2.539   Mean   :0.08747  
 3rd Qu.: 9.20   3rd Qu.:0.6400   3rd Qu.:0.420   3rd Qu.: 2.600   3rd Qu.:0.09000  
 Max.   :15.90   Max.   :1.5800   Max.   :1.000   Max.   :15.500   Max.   :0.61100  
 free.sulfur.dioxide total.sulfur.dioxide    density             pH       
 Min.   : 1.00       Min.   :  6.00       Min.   :0.9901   Min.   :2.740  
 1st Qu.: 7.00       1st Qu.: 22.00       1st Qu.:0.9956   1st Qu.:3.210  
 Median :14.00       Median : 38.00       Median :0.9968   Median :3.310  
 Mean   :15.87       Mean   : 46.47       Mean   :0.9967   Mean   :3.311  
 3rd Qu.:21.00       3rd Qu.: 62.00       3rd Qu.:0.9978   3rd Qu.:3.400  
 Max.   :72.00       Max.   :289.00       Max.   :1.0037   Max.   :4.010  
   sulphates         alcohol      quality
 Min.   :0.3300   Min.   : 8.40   3: 10  
 1st Qu.:0.5500   1st Qu.: 9.50   4: 53  
 Median :0.6200   Median :10.20   5:681  
 Mean   :0.6581   Mean   :10.42   6:638  
 3rd Qu.:0.7300   3rd Qu.:11.10   7:199  
 Max.   :2.0000   Max.   :14.90   8: 18  

Fixed acidity values range between 0.1 and 1.6, with most values range between 0.3 and 0.7. The distribution is slightly positively skewed. When zoom in to values below 1, the distribution seems normal.

2.4 Citric Acid

Found in small quantities, citric acid can add ‘freshness’ and flavor to wines.

# Function to plot histogram of a single variable
plot_uni_var <- function(variable, bins = 50) {
  return (ggplot(aes_string(x = variable), data = wine_reds) + 
            geom_histogram(bins = bins))
}
ggplot(aes(x = quality), data = wine_reds) + 
  geom_bar()

Citric acid values range between 0 and 1 with most values below 0.6. There are 132 red wines in our data set with no detectable citric acid concentration.

2.5 Residual Sugar

The amount of sugar remaining after fermentation stops, it is rare to find wines with less than 1 gram/liter and wines with greater than 45 grams/liter are considered sweet.

plot_uni_var('fixed.acidity')

plot_uni_var('fixed.acidity') + scale_x_log10()

Most residual sugar values range between 1.5 and 2.5. There are a few outliers with large values. When zoom in and look at values below 5, the distribution appears normal.

2.6 Chlorides

The amount of salt in the wine.

plot_uni_var('volatile.acidity')

plot_uni_var('volatile.acidity') + scale_x_continuous(limits = c(0, 1))

Most chlorides values range between 0.05 to 0.1. There are a few outliers with large values. When zoom in and look at values below 0.2, the distribution appears normal.

2.7 Free Sulfur Dioxide

The free form of SO2 exists in equilibrium between molecular SO2 (as a dissolved gas) and bisulfite ion; it prevents microbial growth and the oxidation of wine.

plot_uni_var('citric.acid')

The distribution of free sulfur dioxide is highly positively skewed.

2.8 Total Sulfur Dioxide

The amount of free and bound forms of S02; in low concentrations, SO2 is mostly undetectable in wine, but at free SO2 concentrations over 50 ppm, SO2 becomes evident in the nose and taste of wine.

# number of red wines with citric acid = 0
dim(wine_reds[wine_reds$citric.acid ==0, ])[1]
[1] 132

The distribution of total sulfur dioxide is higly positively skewed. And there are a few outliers with very large values. Transforming the x-axis into log scale can make it more normally distributed.

2.9 Density

The density of wine is close to that of water depending on the percent alcohol and sugar content.

plot_uni_var('residual.sugar')

plot_uni_var('residual.sugar') + scale_x_continuous(limits = c(0, 5))

Density values range between 0.990 and 1.004 with most values range from 0.995 and 0.998. The distribution of density values are symmetrical centered around 0.9965.

2.10 pH

Describes how acidic or basic a wine is on a scale from 0 (very acidic) to 14 (very basic); most wines are between 3-4 on the pH scale.

plot_uni_var('chlorides')

plot_uni_var('chlorides') + scale_x_continuous(limits = c(0, 0.2))

Most pH values range between 3.15 and 3.45. The distribution of pH is symmetrical centered around 3.3.

2.11 Sulphates

A wine additive which can contribute to sulfur dioxide gas (S02) levels, wich acts as an antimicrobial and antioxidant.

plot_uni_var('free.sulfur.dioxide')

Most sulphates values range between 0.5 and 0.75. The distribution is positively skewed. There are a few ourliers with large sulphates values. Transforming the x-axis into log scale can make it more normally distributed.

2.12 Alcohol

The percent alcohol content of the wine

plot_uni_var('total.sulfur.dioxide')

plot_uni_var('total.sulfur.dioxide') + scale_x_log10()

The alcohol values range between 8.5 and 15. The distribution of alcohol value is positively skewed.

3 Univariate Analysis

What is the structure of your dataset?

There are 12 attributes in the dataset. 11 of them (fixed acidity, volatile acidity, citric acid, residual sugar, chlorides, free sulfur dioxide, total sulfur dioxide, density, pH, sulphates, alcohol) are input attributes based on physicochemical tests. The other attribute (quality) is the output attribute based on sensory data. Each row corresponds to one particular wine with total 1599 different red wines in the data set.

What is/are the main feature(s) of interest in your dataset?

The main feature of interest is the output attribute quality. I am trying to figure out which of the 11 input attribute contribute to a high quality value.

What other features in the dataset do you think will help support your investigation into your feature(s) of interest?

The 11 input attributes are equally likely to contribute to the quality value at this point. I will look more closely at how each of the attributes is distributed with a given quality value in the bivariate exploration section.

Did you create any new variables from existing variables in the dataset?

No.

Of the features you investigated, were there any unusual distributions? Did you perform any operations on the data to tidy, adjust, or change the form of the data? If so, why did you do this?

The possible quality values are from 0 to 10, but our data set only has quality values from 3 to 8, which means there are no extremely bad red wines or extrememly good wines in out data set. The vast majority of red wines in the data set has a quality value either 5 or 6, with very fewer wines with quality values 3, 4, 7 or 8, which makes the data set unbalanced.

4 Bivariate Exploration Part I

In this section, I will look at how each input attribute is related to the output quanlity variable.

plot_uni_var('density')

4.1 Quality vs Fixed Acidity

plot_uni_var('pH')

There isn’t a clear trend between fixed acidity and quality.

4.2 Quality vs Volatile Acidity

plot_uni_var('sulphates')

plot_uni_var('sulphates') + scale_x_log10()

The higher the quality, the lower the volatile acidity.

4.3 Quality vs Citric Acid

plot_uni_var('alcohol')

The higher the quality, the higher the citric acid.

4.4 Quality vs Residual Sugar

# Function to plot boxplot of variable grouped by quality
plot_quality_vs_var <- function(variable) {
  # Uncomment the next line to print a summary of variable grouped by quality values
  # print (by(wine_reds[[variable]], wine_reds$quality, summary))
  return (ggplot(aes_string(x = 'quality', y = variable), data = wine_reds) + 
            geom_boxplot())
}

There isn’t a clear trend between residual sugar and quality.

4.5 Quality vs Chlorides

plot_quality_vs_var('fixed.acidity')

After zoom in, one can see the higher the quality, the lower the chlorides.

4.6 Quality vs Free Sulfur Dioxide

plot_quality_vs_var('volatile.acidity')

There isn’t a clear trend between free sulfur dioxide and quality.

4.7 Quality vs Total Sulfur Dioxide

plot_quality_vs_var('citric.acid')

There isn’t a clear trend between total sulfur dioxide and quality.

4.8 Quality vs Density

plot_quality_vs_var('residual.sugar')

The higher the quality, the lower the density.

4.9 Quality vs pH

plot_quality_vs_var('chlorides')

plot_quality_vs_var('chlorides') + scale_y_continuous(limits = c(0.05, 0.15))

The higher the quality, the lower the pH.

4.10 Quality vs Sulphates

plot_quality_vs_var('free.sulfur.dioxide')

The higher the quality, the higher the sulphates.

4.11 Quality vs Alcohol

plot_quality_vs_var('total.sulfur.dioxide')

The higher the quality, the higher the alcohol.

5 Bivariate Exploration Part II

In this section, I will first plot the correlation matrix to find out if there are any interesting pairs of input attributes that look interesting. Then I will examine these pairs.

5.1 Correlation Matrix

plot_quality_vs_var('density')

There are a few pairs of input variables deserve further examing from the correlation matrix plot: fixed acidity vs citric acid, fixed acidity vs density, fixed acidity vs pH, volatile acidity vs citric acid, citric acid vs pH, total sulfur dioxide vs free sulfur dioxide, density vs alcohol.

plot_quality_vs_var('pH')

5.2 Fixed Acidity vs Citric Acid

plot_quality_vs_var('sulphates')

Fixed acidity and citric acid have a correlation coefficient of 0.6717034. This is probably because citric acid is also a kind of fixed acidity.

5.3 Volatile Acidity vs Citric Acid

plot_quality_vs_var('alcohol')

Volatile acidity and citric acid have a correlation coefficient of -0.5524957. I cannot think of an explaination for this correlation.

5.4 pH vs log10(Fixed Acidity)

cor_matrix <- cor(wine_reds[, 1:11])
corrplot(cor_matrix, type = 'lower')

The pH scale is logarithmic, so I first transform fixed acidity into log10(fixed acidity). log10(fixed acidity) and pH have a correlation coefficient of -0.7063602. This is because hihger fixed acidity concentration leads to lower pH values.

5.5 pH vs Citric Acid

# Function to plot scatter plot of variable2 vs variable1
plot_bi_var <- function(variable1, variable2) {
  return (ggplot(aes_string(x = variable1, y = variable2), data = wine_reds) + 
    geom_point(alpha = 1/4, position = position_jitter(width = 0)))
}

Citric acid and pH have a correlation coefficient of -0.5419041. Because we have 132 wines with 0 citric acid values, we cannot perform a logarithmic transfrom here. The correaltion is due to citric acid is non volatile, therefore higher citiric acid concentration leads to lower pH value.

5.6 Total Sulfur Dioxide vs Free Sulfur Dioxide

plot_bi_var('citric.acid', 'fixed.acidity')

cor(wine_reds$citric.acid, wine_reds$fixed.acidity)
[1] 0.6717034

Total sulfur dioxide and free sulfur dioxide have a correlation coefficient of 0.6676665. This is because free sulfur dioxide is part of total sulfur dioxide, and this can also be seen from all the points are above the y=x line.

5.7 Density vs Alcohol

plot_bi_var('citric.acid', 'volatile.acidity')

cor(wine_reds$citric.acid, wine_reds$volatile.acidity)
[1] -0.5524957

Density and alcohol have a correlation coefficient of -0.4961798. This is probably because alcohol has a lower density comparing to water. Therefore, the higher concentration of alcohol, the lower the wine density is.

5.8 Density vs Fixed Acidity

plot_bi_var('log10(fixed.acidity)', 'pH')

cor(log10(wine_reds$fixed.acidity), wine_reds$pH)
[1] -0.7063602

Densidy and fixed acidity have a correlation coefficient of 0.6680473. This is probably because fixed acidity in wine is mainly tartaric acid, and tartaric acid has a density of 1.79 g/mL, which is greater than the wine’s main component–water. Therefore, higher concentration of fixed acidity leads to higher density value.

6 Bivariate Analysis

Talk about some of the relationships you observed in this part of the investigation. How did the feature(s) of interest vary with other features in the dataset?

There are a few attributes exhibit some trends that look promising to be used to predict quality.

We can summarize these relations in the following table:

Attribute Name Relation with Quality
fixed acidity ~
volatile acidity -
citric acid +
residual sugar ~
chlorides -
free sulfur dioxide ~
total sulfur dioxide ~
density -
pH -
sulphates +
alcohol +

Did you observe any interesting relationships between the other features (not the main feature(s) of interest)?

There are a few attributes that are correlated based on physical and chemical principles:

What was the strongest relationship you found?

Observing from the plot, volatile acidity has the strongest relationship with quality.

7 Multivariate Exploration Part I

In this section, I will first look at how quality, volatile acidity and one other input variable are related.

plot_bi_var('citric.acid', 'pH')

cor(wine_reds$citric.acid, wine_reds$pH)
[1] -0.5419041

7.1 Quality vs Volatile Acidity and Citric Acid

plot_bi_var('free.sulfur.dioxide', 'total.sulfur.dioxide') + geom_abline(slope=1)

cor(wine_reds$free.sulfur.dioxide, wine_reds$total.sulfur.dioxide)
[1] 0.6676665

High quality wines tend to have low volatile acidity and high citric acid (upper left corner); low quality wines tend to have high volatile acidity and low citric acid ( lower right corner).

7.2 Quality vs Volatile Acidity and Sulphates

plot_bi_var('alcohol', 'density')

cor(wine_reds$alcohol, wine_reds$density)
[1] -0.4961798

High quality wines tend to have low volatile acidity and high sulphates (lower right corner); low quality wines tend to have high volatile acidity and low sulphates (upper left corner).

7.3 Quality vs Volatile Acidity and Alcohol

plot_bi_var('fixed.acidity', 'density')

cor(wine_reds$fixed.acidity, wine_reds$density)
[1] 0.6680473

High quality wines tend to have low volatile acidity and high alcohol (lower right corner); low quality wines tend to have high volatile acidity and low alcohol (upper left corner).

7.4 Quality vs Volatile Acidity and Chlorides

# Function to plot scatter plot of variable2 vs variable1 colored by quality
plot_quality_vs_two_var <- function(variable1, variable2) {
  ggplot(aes_string(x = variable1, y = variable2, color = 'quality'), data = wine_reds) +
    geom_jitter(alpha = 1/2) +
    scale_color_brewer(type = 'div')
}

High quality wines tend to have low volatile acidity and low chlorides (lower left corner); low quality wines tend to have high volatile acidity and high chlorides (upper right corner).

7.5 Quality vs Volatile Acidity and Density

plot_quality_vs_two_var('volatile.acidity', 'citric.acid')

High quality wines tend to have low volatile acidity and low density (lower left corner); low quality wines tend to have high volatile acidity and high density (upper right corner).

7.6 Quality vs Volatile Acidity and pH

plot_quality_vs_two_var('sulphates', 'volatile.acidity')

High quality wines tend to have low volatile acidity and low pH (lower left corner); low quality wines tend to have high volatile acidity and high pH (upper right corner).

8 Multivariate Exploration Part II

In this section, I will examine the relation among some of input variable triplets.

plot_quality_vs_two_var('alcohol', 'volatile.acidity')

plot_quality_vs_two_var('chlorides', 'volatile.acidity') + 
  scale_x_continuous(limits = c(0, 0.2))

8.1 pH vs Fixed Acidity and Citric Acid

plot_quality_vs_two_var('density', 'volatile.acidity')

Fixed acidity and citric acid both contribute to wines’ pH values. The lower both acids concentrations, the higher the pH (lower left corner), and the higher both acides concentrations, the lower the pH (upper right corner).

8.2 Density vs Alcohol and Fixed Acidity

plot_quality_vs_two_var('pH', 'volatile.acidity')

Fixed acidity is positively correlated with density, and alcohol is negatively correlated with density. We can see from the plot that fixed acidity has a larger impact on the density of wine than alcohol. Because for a given alcohol value, the density increases as fixed acidity increases, whereas for a given fixed acidity value, the density does not change as the alcohol increases.

9 Linear Models

In order to fit a linear model, I will convert quality from ordered factors back into real numbers.

# Function to cut given column from wine_reds data set into quartiles
cut_quartiles <- function(var_to_cut) {
  return (cut(wine_reds[[var_to_cut]], 
              breaks = quantile(wine_reds[[var_to_cut]], 
                                probs = seq(0, 1, 0.25),
                                na.rm = TRUE),
                                include.lowest = TRUE))
}

As one can see, the most promising attribute volatile acidicy alone has R-squared value of 0.153. By adding the other 6 promsing attributes, R-squared value is a little more than doubled becoming 0.350. But adding the rest 4 attributes only increases the R-squared value a little to 0.361.

10 Multivariate Analysis

Talk about some of the relationships you observed in this part of the investigation. Were there features that strengthened each other in terms of looking at your feature(s) of interest?

By combining the most promising attribute from bivariate section, volatile acidity, with one of the other attributes (citric acid, sulphates, alcohol, chlorides, density and pH), one can further separate high quality wines and low quality wines.

Were there any interesting or surprising interactions between features?

By looking at density vs fixed acidity and alcohol, one can see that fixed acidity has a larger impact on the density of the wine than alcohol.

OPTIONAL: Did you create any models with your dataset? Discuss the strengths and limitations of your model.

I created three linear models to predict the output attribute quality. The strength of the model is that it is a simple linear model and it is easy to interpret. However, because the quality values are discrete integer values, the model is less accurate comparing to a more nuanced continuous quality value model. Also due to the limitation of the dataset, only physical and chemical attributes are available, and other import attributes, such as price, color, smell, etc are missing. The other attributes may influence the quality values to a large extent.

11 Final Plots

11.1 Plot I

# Function to plot scatter plot of variable2 vs variable1 colored by variable3
plot_tri_var <- function(variable1, variable2, variable3){
  ggplot(aes_string(x = variable1, y = variable2, color = variable3),
         data = wine_reds) + 
    geom_jitter() + 
    scale_color_brewer(type = 'seq') + 
    theme_dark()
}

The possible quality values are ranging from 0 to 10, however, all red wines in the dataset have quality values between 3 and 8. There is no any really bad wine with quality below 3 or any really good wine with quality above 8. Also, most of the red wines have quality 5 or 6, which make the dataset not well balanced.

11.2 Plot II

wine_reds$pH_quantiles <- cut_quantiles('pH')
plot_tri_var('citric.acid', 'fixed.acidity', 'pH_quantiles')

Excluding the upper 1% outliers, one can see from the plot that higher quality wines (dark green) tend to have low volatile acidity and high sulphates (lower right corner), while lower quality wines (dark brown) tend to have high volatile acidity and low sulphates (upper left corner).

11.3 Plot III

wine_reds$density_quartiles <- cut_quartiles('density')
plot_tri_var('alcohol', 'fixed.acidity', 'density_quartiles')

Fixed acidity is positively correlated with density, and alcohol is negatively correlated with density. The fixed acidity has a larger impact on the density of wine than alcohol. Because for a given alcohol value, the density increases (from light blue to dark blue) as fixed acidity increases, whereas for a given fixed acidity value, the density does not change much as the alcohol increases.

12 Reflection

The red wine data set has 11 input physicochemical attributes and 1 quality output attribute. Throughout the analysis, I focused on answering two quations:

I ran into difficulties when answering question 1. There were many combinations of the 11 input attributes I could pick to plot against the quality attribute. But I did not have good criteria to determine the order of importance of these attributes. I relied on visualization and chose the volatile acidicy as the most promising attribute and used it as the fixed attribute during multivariate plot section.

I did observe some good results when answering question 2. The plots showing between and among different input physicochemical attributes were in accordance with actual physical and chemical properties and laws, such high acid concentration correlates with low pH, and high alcohol percent correlates with low density.

I believe by incorporating other types of attributes, such as price, color and smell, I can build a better model to predict the quality of wine than using only physicochemical attributes. Also, one more interesting project can be combining the red wine data set with the white wine data set, and to find out if attributes correlate to high quality red wines also correlate to high quality white wines.

LS0tCnRpdGxlOiAiRXhwbG9yZSBSZWQgV2luZSBEYXRhIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBzZWxmX2NvbnRhaW5lZDogbm8KICAgIHRvYzogeWVzCiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2M6IHllcwotLS0KCiMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIHJlcG9ydCwgSSB3aWxsIGV4cGxvcmUgdGhlIHJlZCB3aW5lIGRhdGFzZXQuIEZpcnN0LCBJIHdpbGwgbG9vayBhdCBlYWNoIGluZGl2aWR1YWwgYXR0cmlidXRlIG9mIHRoaXMgZGF0YXNldCBhbmQgcGxvdCBpdHMgZGlzdHJpYnV0aW9uLiBTZWNvbmQsIEkgd2lsbCBsb29rIGF0IHR3byBhdHRyaWJ1dGVzIGF0IGEgdGltZSB0byBleHBsb3JlIDEpIGhvdyBlYWNoIGlucHV0IGF0dHJpYnV0ZSBpcyByZWxhdGVkIHRvIHRoZSBvdXRwdXQgYXR0cmlidXRlLS1xdWFsaXR5OyAyKSBpbnRlcmVzdGluZyBwYWlycyBvZiBpbnB1dCBhdHRyaWJ1dGVzLiBUaGlyZCwgSSB3aWxsIGV4YW1pbmUgdGhyZWUgYXR0cmlidXRlcyBieSBhZGRpbmcgb25lIGFkZGl0aW9uYWwgYXR0cmlidXRlIHRvIHNvbWUgb2YgdGhlIGludGVyZXN0aW5nIHR3by1hdHRyaWJ1dGUgcGFpcnMuIEZpbmFsbHksIEkgd2lsbCBzdW1tYXJpemUgdGhlIHN1Y2Nlc3NlcyBhbmQgcHJvYmxlbXMgSSBlbmNvdW50ZXIgZHVyaW5nIHRoZSBkYXRhIGV4cGxvcmF0aW9uIHByb2Nlc3MuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgcGFja2FnZXN9CiMgTG9hZCBhbGwgb2YgdGhlIHBhY2thZ2VzIGluIHRoaXMgY29kZSBjaHVuay4KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvcnJwbG90KQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShtZW1pc2MpCmBgYAoKYGBge3J9CiMgTG9hZCB0aGUgRGF0YQp3aW5lX3JlZHMgPSByZWFkLmNzdignd2luZVF1YWxpdHlSZWRzLmNzdicsIHJvdy5uYW1lcyA9IDEpCmBgYAoKIyBVbml2YXJpYXRlIEV4cGxvcmF0aW9uCgpJbiB0aGlzIHNlY3Rpb24sIEkgd2lsbCBmaXJzdCBsb29rIGF0IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGEgc2V0LiBUaGVuIEkgd2lsbCBleGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgZWFjaCBhdHRyaWJ1dGUgaW5kaXZpZHVhbGx5IGJ5IHBsb3R0aW5nIGl0cyBkaXN0cmlidXRpb24uCgpgYGB7ciwgRGF0YV9EaW1lbnNpb25zfQpkaW0od2luZV9yZWRzKQpgYGAKCmBgYHtyLCBEYXRhX1N0cnVjdHVyZX0KIyBDb252ZXJ0IHF1YWxpdHkgaW50byBvcmRlcmVkIGNhdGVnb3JpY2FsIHZhcmlhYmxlCndpbmVfcmVkcyRxdWFsaXR5IDwtIG9yZGVyZWQod2luZV9yZWRzJHF1YWxpdHkpCnN0cih3aW5lX3JlZHMpCmBgYAoKYGBge3IsIERhdGFfU3VtbWFyeX0Kc3VtbWFyeSh3aW5lX3JlZHMpCmBgYAoKVGhlIHJlZCB3aW5lIGRhdGFzZXQgY29udGFpbnMgMTIgdmFyaWFibGVzLS0xMSBpbnB1dCBudW1lcmljYWwgdmFyaWFibGVzIGJhc2VkIG9uIHBoeXNpY29jaGVtaWNhbCB0ZXN0cyBhbmQgMSBjYXRlZ29yaWNhbCBvdXRwdXQgdmFyaWFibGUgKHF1YWxpdHkpIGJhc2VkIG9uIHNlbnNvcnkgZGF0YSwgd2l0aCAxNTk5IG9ic2VydmF0aW9ucy4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHBsb3QgaGlzdG9ncmFtIG9mIGEgc2luZ2xlIHZhcmlhYmxlCnBsb3RfdW5pX3ZhciA8LSBmdW5jdGlvbih2YXJpYWJsZSwgYmlucyA9IDUwKSB7CiAgcmV0dXJuIChnZ3Bsb3QoYWVzX3N0cmluZyh4ID0gdmFyaWFibGUpLCBkYXRhID0gd2luZV9yZWRzKSArIAogICAgICAgICAgICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gYmlucykpCn0KYGBgCgojIyBRdWFsaXR5CmBgYHtyfQpnZ3Bsb3QoYWVzKHggPSBxdWFsaXR5KSwgZGF0YSA9IHdpbmVfcmVkcykgKyAKICBnZW9tX2JhcigpCmBgYAoKT3V0IG9mIHRoZSBwb3NzaWJsZSBxdWFsaXR5IHNjb3JlcyBiZXR3ZWVuIDAgYW5kIDEwLCBhbGwgb2Ygb3VyIHJlZCB3aW5lcycgcXVhbGl0eSBzY29yZXMgZmFsbCBiZXR3ZWVuIDMgYW5kIDguIFRoZSBkYXRhc2V0IGlzIG5vdCB3ZWxsIGJhbGFuY2VkLiBNYWpvcml0eSBvZiByZWQgd2luZXMgaGF2ZSBhIHF1YWxpdHkgc2NvcmUgb2YgZWl0aGVyIDUgb3IgNi4gSSBhbSBjdXJpb3VzIGFib3V0IHdoYXQgYXR0cmlidXRlcyBtYWtlIGEgd2luZSBlYXJuIGEgbG93IHF1YWxpdHkgc2NvcmUgKHF1YWxpdHkgPSAzKSBvciBhIGhpZ2ggcXVhbGl0eSBzY29yZSAocXVhbGl0eSA9IDgpLgoKIyMgRml4ZWQgQWNpZGl0eQpNb3N0IGFjaWRzIGludm9sdmVkIHdpdGggd2luZSBhcmUgZml4ZWQgb3Igbm9udm9sYXRpbGUgKGRvIG5vdCBldmFwb3JhdGUgcmVhZGlseSkuCmBgYHtyfQpwbG90X3VuaV92YXIoJ2ZpeGVkLmFjaWRpdHknKQpwbG90X3VuaV92YXIoJ2ZpeGVkLmFjaWRpdHknKSArIHNjYWxlX3hfbG9nMTAoKQpgYGAKCkZpeGVkIGFjaWRpdHkgdmFsdWVzIHJhbmdlIGJldHdlZW4gNCBhbmQgMTYsIHdpdGggbW9zdCB2YWx1ZXMgcmFuZ2UgYmV0d2VlbiA3IGFuZCA5LiBUaGUgZGlzdHJpYnV0aW9uIGlzIHNsaWdodGx5IHBvc2l0aXZlbHkgc2tld2VkLiBUcmFuc2Zvcm1pbmcgdGhlIHgtYXhpcyBpbnRvIGxvZyBzY2FsZSBjYW4gbWFrZSBpdCBtb3JlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMgVm9sYXRpbGUgQWNpZGl0eQpUaGUgYW1vdW50IG9mIGFjZXRpYyBhY2lkIGluIHdpbmUsIHdoaWNoIGF0IHRvbyBoaWdoIG9mIGxldmVscyBjYW4gbGVhZCB0byBhbiB1bnBsZWFzYW50LCB2aW5lZ2FyIHRhc3RlLgpgYGB7cn0KcGxvdF91bmlfdmFyKCd2b2xhdGlsZS5hY2lkaXR5JykKcGxvdF91bmlfdmFyKCd2b2xhdGlsZS5hY2lkaXR5JykgKyBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxKSkKYGBgCgpGaXhlZCBhY2lkaXR5IHZhbHVlcyByYW5nZSBiZXR3ZWVuIDAuMSBhbmQgMS42LCB3aXRoIG1vc3QgdmFsdWVzIHJhbmdlIGJldHdlZW4gMC4zIGFuZCAwLjcuIFRoZSBkaXN0cmlidXRpb24gaXMgc2xpZ2h0bHkgcG9zaXRpdmVseSBza2V3ZWQuIFdoZW4gem9vbSBpbiB0byB2YWx1ZXMgYmVsb3cgMSwgdGhlIGRpc3RyaWJ1dGlvbiBzZWVtcyBub3JtYWwuCgojIyBDaXRyaWMgQWNpZApGb3VuZCBpbiBzbWFsbCBxdWFudGl0aWVzLCBjaXRyaWMgYWNpZCBjYW4gYWRkICdmcmVzaG5lc3MnIGFuZCBmbGF2b3IgdG8gd2luZXMuCmBgYHtyfQpwbG90X3VuaV92YXIoJ2NpdHJpYy5hY2lkJykKYGBgCgpgYGB7cn0KIyBudW1iZXIgb2YgcmVkIHdpbmVzIHdpdGggY2l0cmljIGFjaWQgPSAwCmRpbSh3aW5lX3JlZHNbd2luZV9yZWRzJGNpdHJpYy5hY2lkID09MCwgXSlbMV0KYGBgCgpDaXRyaWMgYWNpZCB2YWx1ZXMgcmFuZ2UgYmV0d2VlbiAwIGFuZCAxIHdpdGggbW9zdCB2YWx1ZXMgYmVsb3cgMC42LiBUaGVyZSBhcmUgMTMyIHJlZCB3aW5lcyBpbiBvdXIgZGF0YSBzZXQgd2l0aCBubyBkZXRlY3RhYmxlIGNpdHJpYyBhY2lkIGNvbmNlbnRyYXRpb24uCgojIyBSZXNpZHVhbCBTdWdhcgpUaGUgYW1vdW50IG9mIHN1Z2FyIHJlbWFpbmluZyBhZnRlciBmZXJtZW50YXRpb24gc3RvcHMsIGl0IGlzIHJhcmUgdG8gZmluZCB3aW5lcyB3aXRoIGxlc3MgdGhhbiAxIGdyYW0vbGl0ZXIgYW5kIHdpbmVzIHdpdGggZ3JlYXRlciB0aGFuIDQ1IGdyYW1zL2xpdGVyIGFyZSBjb25zaWRlcmVkIHN3ZWV0LgpgYGB7cn0KcGxvdF91bmlfdmFyKCdyZXNpZHVhbC5zdWdhcicpCnBsb3RfdW5pX3ZhcigncmVzaWR1YWwuc3VnYXInKSArIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDUpKQpgYGAKCk1vc3QgcmVzaWR1YWwgc3VnYXIgdmFsdWVzIHJhbmdlIGJldHdlZW4gMS41IGFuZCAyLjUuIFRoZXJlIGFyZSBhIGZldyBvdXRsaWVycyB3aXRoIGxhcmdlIHZhbHVlcy4gV2hlbiB6b29tIGluIGFuZCBsb29rIGF0IHZhbHVlcyBiZWxvdyA1LCB0aGUgZGlzdHJpYnV0aW9uIGFwcGVhcnMgbm9ybWFsLgoKIyMgQ2hsb3JpZGVzClRoZSBhbW91bnQgb2Ygc2FsdCBpbiB0aGUgd2luZS4KYGBge3J9CnBsb3RfdW5pX3ZhcignY2hsb3JpZGVzJykKcGxvdF91bmlfdmFyKCdjaGxvcmlkZXMnKSArIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDAuMikpCmBgYAoKTW9zdCBjaGxvcmlkZXMgdmFsdWVzIHJhbmdlIGJldHdlZW4gMC4wNSB0byAwLjEuIFRoZXJlIGFyZSBhIGZldyBvdXRsaWVycyB3aXRoIGxhcmdlIHZhbHVlcy4gV2hlbiB6b29tIGluIGFuZCBsb29rIGF0IHZhbHVlcyBiZWxvdyAwLjIsIHRoZSBkaXN0cmlidXRpb24gYXBwZWFycyBub3JtYWwuCgojIyBGcmVlIFN1bGZ1ciBEaW94aWRlClRoZSBmcmVlIGZvcm0gb2YgU08yIGV4aXN0cyBpbiBlcXVpbGlicml1bSBiZXR3ZWVuIG1vbGVjdWxhciBTTzIgKGFzIGEgZGlzc29sdmVkIGdhcykgYW5kIGJpc3VsZml0ZSBpb247IGl0IHByZXZlbnRzIG1pY3JvYmlhbCBncm93dGggYW5kIHRoZSBveGlkYXRpb24gb2Ygd2luZS4KYGBge3J9CnBsb3RfdW5pX3ZhcignZnJlZS5zdWxmdXIuZGlveGlkZScpCmBgYAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBmcmVlIHN1bGZ1ciBkaW94aWRlIGlzIGhpZ2hseSBwb3NpdGl2ZWx5IHNrZXdlZC4KCiMjIFRvdGFsIFN1bGZ1ciBEaW94aWRlClRoZSBhbW91bnQgb2YgZnJlZSBhbmQgYm91bmQgZm9ybXMgb2YgUzAyOyBpbiBsb3cgY29uY2VudHJhdGlvbnMsIFNPMiBpcyBtb3N0bHkgdW5kZXRlY3RhYmxlIGluIHdpbmUsIGJ1dCBhdCBmcmVlIFNPMiBjb25jZW50cmF0aW9ucyBvdmVyIDUwIHBwbSwgU08yIGJlY29tZXMgZXZpZGVudCBpbiB0aGUgbm9zZSBhbmQgdGFzdGUgb2Ygd2luZS4KCmBgYHtyfQpwbG90X3VuaV92YXIoJ3RvdGFsLnN1bGZ1ci5kaW94aWRlJykKcGxvdF91bmlfdmFyKCd0b3RhbC5zdWxmdXIuZGlveGlkZScpICsgc2NhbGVfeF9sb2cxMCgpCmBgYAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiB0b3RhbCBzdWxmdXIgZGlveGlkZSBpcyBoaWdseSBwb3NpdGl2ZWx5IHNrZXdlZC4gQW5kIHRoZXJlIGFyZSBhIGZldyBvdXRsaWVycyB3aXRoIHZlcnkgbGFyZ2UgdmFsdWVzLiBUcmFuc2Zvcm1pbmcgdGhlIHgtYXhpcyBpbnRvIGxvZyBzY2FsZSBjYW4gbWFrZSBpdCBtb3JlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMgRGVuc2l0eQpUaGUgZGVuc2l0eSBvZiB3aW5lIGlzIGNsb3NlIHRvIHRoYXQgb2Ygd2F0ZXIgZGVwZW5kaW5nIG9uIHRoZSBwZXJjZW50IGFsY29ob2wgYW5kIHN1Z2FyIGNvbnRlbnQuCmBgYHtyfQpwbG90X3VuaV92YXIoJ2RlbnNpdHknKQpgYGAKCkRlbnNpdHkgdmFsdWVzIHJhbmdlIGJldHdlZW4gMC45OTAgYW5kIDEuMDA0IHdpdGggbW9zdCB2YWx1ZXMgcmFuZ2UgZnJvbSAwLjk5NSBhbmQgMC45OTguIFRoZSBkaXN0cmlidXRpb24gb2YgZGVuc2l0eSB2YWx1ZXMgYXJlIHN5bW1ldHJpY2FsIGNlbnRlcmVkIGFyb3VuZCAwLjk5NjUuCgojIyBwSApEZXNjcmliZXMgaG93IGFjaWRpYyBvciBiYXNpYyBhIHdpbmUgaXMgb24gYSBzY2FsZSBmcm9tIDAgKHZlcnkgYWNpZGljKSB0byAxNCAodmVyeSBiYXNpYyk7IG1vc3Qgd2luZXMgYXJlIGJldHdlZW4gMy00IG9uIHRoZSBwSCBzY2FsZS4KYGBge3J9CnBsb3RfdW5pX3ZhcigncEgnKQpgYGAKCk1vc3QgcEggdmFsdWVzIHJhbmdlIGJldHdlZW4gMy4xNSBhbmQgMy40NS4gVGhlIGRpc3RyaWJ1dGlvbiBvZiBwSCBpcyBzeW1tZXRyaWNhbCBjZW50ZXJlZCBhcm91bmQgMy4zLgoKIyMgU3VscGhhdGVzCkEgd2luZSBhZGRpdGl2ZSB3aGljaCBjYW4gY29udHJpYnV0ZSB0byBzdWxmdXIgZGlveGlkZSBnYXMgKFMwMikgbGV2ZWxzLCB3aWNoIGFjdHMgYXMgYW4gYW50aW1pY3JvYmlhbCBhbmQgYW50aW94aWRhbnQuCmBgYHtyfQpwbG90X3VuaV92YXIoJ3N1bHBoYXRlcycpCnBsb3RfdW5pX3Zhcignc3VscGhhdGVzJykgKyBzY2FsZV94X2xvZzEwKCkKYGBgCgpNb3N0IHN1bHBoYXRlcyB2YWx1ZXMgcmFuZ2UgYmV0d2VlbiAwLjUgYW5kIDAuNzUuIFRoZSBkaXN0cmlidXRpb24gaXMgcG9zaXRpdmVseSBza2V3ZWQuIFRoZXJlIGFyZSBhIGZldyBvdXJsaWVycyB3aXRoIGxhcmdlIHN1bHBoYXRlcyB2YWx1ZXMuIFRyYW5zZm9ybWluZyB0aGUgeC1heGlzIGludG8gbG9nIHNjYWxlIGNhbiBtYWtlIGl0IG1vcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuCgojIyBBbGNvaG9sClRoZSBwZXJjZW50IGFsY29ob2wgY29udGVudCBvZiB0aGUgd2luZQpgYGB7cn0KcGxvdF91bmlfdmFyKCdhbGNvaG9sJykKYGBgCgpUaGUgYWxjb2hvbCB2YWx1ZXMgcmFuZ2UgYmV0d2VlbiA4LjUgYW5kIDE1LiBUaGUgZGlzdHJpYnV0aW9uIG9mIGFsY29ob2wgdmFsdWUgaXMgcG9zaXRpdmVseSBza2V3ZWQuCgojIFVuaXZhcmlhdGUgQW5hbHlzaXMKCioqV2hhdCBpcyB0aGUgc3RydWN0dXJlIG9mIHlvdXIgZGF0YXNldD8qKgoKVGhlcmUgYXJlIDEyIGF0dHJpYnV0ZXMgaW4gdGhlIGRhdGFzZXQuIDExIG9mIHRoZW0gKGZpeGVkIGFjaWRpdHksIHZvbGF0aWxlIGFjaWRpdHksIGNpdHJpYyBhY2lkLCByZXNpZHVhbCBzdWdhciwgY2hsb3JpZGVzLCBmcmVlIHN1bGZ1ciBkaW94aWRlLCB0b3RhbCBzdWxmdXIgZGlveGlkZSwgZGVuc2l0eSwgcEgsIHN1bHBoYXRlcywgYWxjb2hvbCkgYXJlIGlucHV0IGF0dHJpYnV0ZXMgYmFzZWQgb24gcGh5c2ljb2NoZW1pY2FsIHRlc3RzLiBUaGUgb3RoZXIgYXR0cmlidXRlIChxdWFsaXR5KSBpcyB0aGUgb3V0cHV0IGF0dHJpYnV0ZSBiYXNlZCBvbiBzZW5zb3J5IGRhdGEuIEVhY2ggcm93IGNvcnJlc3BvbmRzIHRvIG9uZSBwYXJ0aWN1bGFyIHdpbmUgd2l0aCB0b3RhbCAxNTk5IGRpZmZlcmVudCByZWQgd2luZXMgaW4gdGhlIGRhdGEgc2V0LgoKKipXaGF0IGlzL2FyZSB0aGUgbWFpbiBmZWF0dXJlKHMpIG9mIGludGVyZXN0IGluIHlvdXIgZGF0YXNldD8qKgoKVGhlIG1haW4gZmVhdHVyZSBvZiBpbnRlcmVzdCBpcyB0aGUgb3V0cHV0IGF0dHJpYnV0ZSBxdWFsaXR5LiBJIGFtIHRyeWluZyB0byBmaWd1cmUgb3V0IHdoaWNoIG9mIHRoZSAxMSBpbnB1dCBhdHRyaWJ1dGUgY29udHJpYnV0ZSB0byBhIGhpZ2ggcXVhbGl0eSB2YWx1ZS4KCioqV2hhdCBvdGhlciBmZWF0dXJlcyBpbiB0aGUgZGF0YXNldCBkbyB5b3UgdGhpbmsgd2lsbCBoZWxwIHN1cHBvcnQgeW91ciBpbnZlc3RpZ2F0aW9uIGludG8geW91ciBmZWF0dXJlKHMpIG9mIGludGVyZXN0PyoqCgpUaGUgMTEgaW5wdXQgYXR0cmlidXRlcyBhcmUgZXF1YWxseSBsaWtlbHkgdG8gY29udHJpYnV0ZSB0byB0aGUgcXVhbGl0eSB2YWx1ZSBhdCB0aGlzIHBvaW50LiBJIHdpbGwgbG9vayBtb3JlIGNsb3NlbHkgYXQgaG93IGVhY2ggb2YgdGhlIGF0dHJpYnV0ZXMgaXMgZGlzdHJpYnV0ZWQgd2l0aCBhIGdpdmVuIHF1YWxpdHkgdmFsdWUgaW4gdGhlIGJpdmFyaWF0ZSBleHBsb3JhdGlvbiBzZWN0aW9uLgoKKipEaWQgeW91IGNyZWF0ZSBhbnkgbmV3IHZhcmlhYmxlcyBmcm9tIGV4aXN0aW5nIHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldD8qKgoKTm8uCgoqKk9mIHRoZSBmZWF0dXJlcyB5b3UgaW52ZXN0aWdhdGVkLCB3ZXJlIHRoZXJlIGFueSB1bnVzdWFsIGRpc3RyaWJ1dGlvbnM/IERpZCB5b3UgcGVyZm9ybSBhbnkgb3BlcmF0aW9ucyBvbiB0aGUgZGF0YSB0byB0aWR5LCBhZGp1c3QsIG9yIGNoYW5nZSB0aGUgZm9ybSBvZiB0aGUgZGF0YT8gSWYgc28sIHdoeSBkaWQgeW91IGRvIHRoaXM/KioKClRoZSBwb3NzaWJsZSBxdWFsaXR5IHZhbHVlcyBhcmUgZnJvbSAwIHRvIDEwLCBidXQgb3VyIGRhdGEgc2V0IG9ubHkgaGFzIHF1YWxpdHkgdmFsdWVzIGZyb20gMyB0byA4LCB3aGljaCBtZWFucyB0aGVyZSBhcmUgbm8gZXh0cmVtZWx5IGJhZCByZWQgd2luZXMgb3IgZXh0cmVtZW1seSBnb29kIHdpbmVzIGluIG91dCBkYXRhIHNldC4gVGhlIHZhc3QgbWFqb3JpdHkgb2YgcmVkIHdpbmVzIGluIHRoZSBkYXRhIHNldCBoYXMgYSBxdWFsaXR5IHZhbHVlIGVpdGhlciA1IG9yIDYsIHdpdGggdmVyeSBmZXdlciB3aW5lcyB3aXRoIHF1YWxpdHkgdmFsdWVzIDMsIDQsIDcgb3IgOCwgd2hpY2ggbWFrZXMgdGhlIGRhdGEgc2V0IHVuYmFsYW5jZWQuCgojIEJpdmFyaWF0ZSBFeHBsb3JhdGlvbiBQYXJ0IEkKCkluIHRoaXMgc2VjdGlvbiwgSSB3aWxsIGxvb2sgYXQgaG93IGVhY2ggaW5wdXQgYXR0cmlidXRlIGlzIHJlbGF0ZWQgdG8gdGhlIG91dHB1dCBxdWFubGl0eSB2YXJpYWJsZS4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHBsb3QgYm94cGxvdCBvZiB2YXJpYWJsZSBncm91cGVkIGJ5IHF1YWxpdHkKcGxvdF9xdWFsaXR5X3ZzX3ZhciA8LSBmdW5jdGlvbih2YXJpYWJsZSkgewogICMgVW5jb21tZW50IHRoZSBuZXh0IGxpbmUgdG8gcHJpbnQgYSBzdW1tYXJ5IG9mIHZhcmlhYmxlIGdyb3VwZWQgYnkgcXVhbGl0eSB2YWx1ZXMKICAjIHByaW50IChieSh3aW5lX3JlZHNbW3ZhcmlhYmxlXV0sIHdpbmVfcmVkcyRxdWFsaXR5LCBzdW1tYXJ5KSkKICByZXR1cm4gKGdncGxvdChhZXNfc3RyaW5nKHggPSAncXVhbGl0eScsIHkgPSB2YXJpYWJsZSksIGRhdGEgPSB3aW5lX3JlZHMpICsgCiAgICAgICAgICAgIGdlb21fYm94cGxvdCgpKQp9CmBgYAoKIyMgUXVhbGl0eSB2cyBGaXhlZCBBY2lkaXR5CmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdmFyKCdmaXhlZC5hY2lkaXR5JykKYGBgCgpUaGVyZSBpc24ndCBhIGNsZWFyIHRyZW5kIGJldHdlZW4gZml4ZWQgYWNpZGl0eSBhbmQgcXVhbGl0eS4KCiMjIFF1YWxpdHkgdnMgVm9sYXRpbGUgQWNpZGl0eQpgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3Zhcigndm9sYXRpbGUuYWNpZGl0eScpCmBgYAoKVGhlIGhpZ2hlciB0aGUgcXVhbGl0eSwgdGhlIGxvd2VyIHRoZSB2b2xhdGlsZSBhY2lkaXR5LgoKIyMgUXVhbGl0eSB2cyBDaXRyaWMgQWNpZApgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3ZhcignY2l0cmljLmFjaWQnKQpgYGAKClRoZSBoaWdoZXIgdGhlIHF1YWxpdHksIHRoZSBoaWdoZXIgdGhlIGNpdHJpYyBhY2lkLgoKIyMgUXVhbGl0eSB2cyBSZXNpZHVhbCBTdWdhcgpgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3ZhcigncmVzaWR1YWwuc3VnYXInKQpgYGAKClRoZXJlIGlzbid0IGEgY2xlYXIgdHJlbmQgYmV0d2VlbiByZXNpZHVhbCBzdWdhciBhbmQgcXVhbGl0eS4KCiMjIFF1YWxpdHkgdnMgQ2hsb3JpZGVzCmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdmFyKCdjaGxvcmlkZXMnKQpwbG90X3F1YWxpdHlfdnNfdmFyKCdjaGxvcmlkZXMnKSArIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAuMDUsIDAuMTUpKQpgYGAKCkFmdGVyIHpvb20gaW4sIG9uZSBjYW4gc2VlIHRoZSBoaWdoZXIgdGhlIHF1YWxpdHksIHRoZSBsb3dlciB0aGUgY2hsb3JpZGVzLgoKIyMgUXVhbGl0eSB2cyBGcmVlIFN1bGZ1ciBEaW94aWRlCmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdmFyKCdmcmVlLnN1bGZ1ci5kaW94aWRlJykKYGBgCgpUaGVyZSBpc24ndCBhIGNsZWFyIHRyZW5kIGJldHdlZW4gZnJlZSBzdWxmdXIgZGlveGlkZSBhbmQgcXVhbGl0eS4KCiMjIFF1YWxpdHkgdnMgVG90YWwgU3VsZnVyIERpb3hpZGUKYGBge3J9CnBsb3RfcXVhbGl0eV92c192YXIoJ3RvdGFsLnN1bGZ1ci5kaW94aWRlJykKYGBgCgpUaGVyZSBpc24ndCBhIGNsZWFyIHRyZW5kIGJldHdlZW4gdG90YWwgc3VsZnVyIGRpb3hpZGUgYW5kIHF1YWxpdHkuCgojIyBRdWFsaXR5IHZzIERlbnNpdHkKYGBge3J9CnBsb3RfcXVhbGl0eV92c192YXIoJ2RlbnNpdHknKQpgYGAKClRoZSBoaWdoZXIgdGhlIHF1YWxpdHksIHRoZSBsb3dlciB0aGUgZGVuc2l0eS4KCiMjIFF1YWxpdHkgdnMgcEgKYGBge3J9CnBsb3RfcXVhbGl0eV92c192YXIoJ3BIJykKYGBgCgpUaGUgaGlnaGVyIHRoZSBxdWFsaXR5LCB0aGUgbG93ZXIgdGhlIHBILgoKIyMgUXVhbGl0eSB2cyBTdWxwaGF0ZXMKYGBge3J9CnBsb3RfcXVhbGl0eV92c192YXIoJ3N1bHBoYXRlcycpCmBgYAoKVGhlIGhpZ2hlciB0aGUgcXVhbGl0eSwgdGhlIGhpZ2hlciB0aGUgc3VscGhhdGVzLgoKIyMgUXVhbGl0eSB2cyBBbGNvaG9sCmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdmFyKCdhbGNvaG9sJykKYGBgCgpUaGUgaGlnaGVyIHRoZSBxdWFsaXR5LCB0aGUgaGlnaGVyIHRoZSBhbGNvaG9sLgoKIyBCaXZhcmlhdGUgRXhwbG9yYXRpb24gUGFydCBJSQoKSW4gdGhpcyBzZWN0aW9uLCBJIHdpbGwgZmlyc3QgcGxvdCB0aGUgY29ycmVsYXRpb24gbWF0cml4IHRvIGZpbmQgb3V0IGlmIHRoZXJlIGFyZSBhbnkgaW50ZXJlc3RpbmcgcGFpcnMgb2YgaW5wdXQgYXR0cmlidXRlcyB0aGF0IGxvb2sgaW50ZXJlc3RpbmcuIFRoZW4gSSB3aWxsIGV4YW1pbmUgdGhlc2UgcGFpcnMuCgojIyBDb3JyZWxhdGlvbiBNYXRyaXgKYGBge3J9CmNvcl9tYXRyaXggPC0gY29yKHdpbmVfcmVkc1ssIDE6MTFdKQpjb3JycGxvdChjb3JfbWF0cml4LCB0eXBlID0gJ2xvd2VyJykKYGBgCgpUaGVyZSBhcmUgYSBmZXcgcGFpcnMgb2YgaW5wdXQgdmFyaWFibGVzIGRlc2VydmUgZnVydGhlciBleGFtaW5nIGZyb20gdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCBwbG90OiBmaXhlZCBhY2lkaXR5IHZzIGNpdHJpYyBhY2lkLCBmaXhlZCBhY2lkaXR5IHZzIGRlbnNpdHksIGZpeGVkIGFjaWRpdHkgdnMgcEgsIHZvbGF0aWxlIGFjaWRpdHkgdnMgY2l0cmljIGFjaWQsIGNpdHJpYyBhY2lkIHZzIHBILCB0b3RhbCBzdWxmdXIgZGlveGlkZSB2cyBmcmVlIHN1bGZ1ciBkaW94aWRlLCBkZW5zaXR5IHZzIGFsY29ob2wuCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBwbG90IHNjYXR0ZXIgcGxvdCBvZiB2YXJpYWJsZTIgdnMgdmFyaWFibGUxCnBsb3RfYmlfdmFyIDwtIGZ1bmN0aW9uKHZhcmlhYmxlMSwgdmFyaWFibGUyKSB7CiAgcmV0dXJuIChnZ3Bsb3QoYWVzX3N0cmluZyh4ID0gdmFyaWFibGUxLCB5ID0gdmFyaWFibGUyKSwgZGF0YSA9IHdpbmVfcmVkcykgKyAKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAxLzQsIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoID0gMCkpKQp9CmBgYAoKIyMgRml4ZWQgQWNpZGl0eSB2cyBDaXRyaWMgQWNpZApgYGB7cn0KcGxvdF9iaV92YXIoJ2NpdHJpYy5hY2lkJywgJ2ZpeGVkLmFjaWRpdHknKQpjb3Iod2luZV9yZWRzJGNpdHJpYy5hY2lkLCB3aW5lX3JlZHMkZml4ZWQuYWNpZGl0eSkKYGBgCgpGaXhlZCBhY2lkaXR5IGFuZCBjaXRyaWMgYWNpZCBoYXZlIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgMC42NzE3MDM0LiBUaGlzIGlzIHByb2JhYmx5IGJlY2F1c2UgY2l0cmljIGFjaWQgaXMgYWxzbyBhIGtpbmQgb2YgZml4ZWQgYWNpZGl0eS4KCiMjIFZvbGF0aWxlIEFjaWRpdHkgdnMgQ2l0cmljIEFjaWQKYGBge3J9CnBsb3RfYmlfdmFyKCdjaXRyaWMuYWNpZCcsICd2b2xhdGlsZS5hY2lkaXR5JykKY29yKHdpbmVfcmVkcyRjaXRyaWMuYWNpZCwgd2luZV9yZWRzJHZvbGF0aWxlLmFjaWRpdHkpCmBgYAoKVm9sYXRpbGUgYWNpZGl0eSBhbmQgY2l0cmljIGFjaWQgaGF2ZSBhIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIC0wLjU1MjQ5NTcuIEkgY2Fubm90IHRoaW5rIG9mIGFuIGV4cGxhaW5hdGlvbiBmb3IgdGhpcyBjb3JyZWxhdGlvbi4gCgojIyBwSCB2cyBsb2cxMChGaXhlZCBBY2lkaXR5KQpgYGB7cn0KcGxvdF9iaV92YXIoJ2xvZzEwKGZpeGVkLmFjaWRpdHkpJywgJ3BIJykKY29yKGxvZzEwKHdpbmVfcmVkcyRmaXhlZC5hY2lkaXR5KSwgd2luZV9yZWRzJHBIKQpgYGAKClRoZSBwSCBzY2FsZSBpcyBsb2dhcml0aG1pYywgc28gSSBmaXJzdCB0cmFuc2Zvcm0gZml4ZWQgYWNpZGl0eSBpbnRvIGxvZzEwKGZpeGVkIGFjaWRpdHkpLiBsb2cxMChmaXhlZCBhY2lkaXR5KSBhbmQgcEggaGF2ZSBhIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIC0wLjcwNjM2MDIuIFRoaXMgaXMgYmVjYXVzZSBoaWhnZXIgZml4ZWQgYWNpZGl0eSBjb25jZW50cmF0aW9uIGxlYWRzIHRvIGxvd2VyIHBIIHZhbHVlcy4KCiMjIHBIIHZzIENpdHJpYyBBY2lkCmBgYHtyfQpwbG90X2JpX3ZhcignY2l0cmljLmFjaWQnLCAncEgnKQpjb3Iod2luZV9yZWRzJGNpdHJpYy5hY2lkLCB3aW5lX3JlZHMkcEgpCmBgYAoKQ2l0cmljIGFjaWQgYW5kIHBIIGhhdmUgYSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAtMC41NDE5MDQxLiBCZWNhdXNlIHdlIGhhdmUgMTMyIHdpbmVzIHdpdGggMCBjaXRyaWMgYWNpZCB2YWx1ZXMsIHdlIGNhbm5vdCBwZXJmb3JtIGEgbG9nYXJpdGhtaWMgdHJhbnNmcm9tIGhlcmUuIFRoZSBjb3JyZWFsdGlvbiBpcyBkdWUgdG8gY2l0cmljIGFjaWQgaXMgbm9uIHZvbGF0aWxlLCB0aGVyZWZvcmUgaGlnaGVyIGNpdGlyaWMgYWNpZCBjb25jZW50cmF0aW9uIGxlYWRzIHRvIGxvd2VyIHBIIHZhbHVlLgoKIyMgVG90YWwgU3VsZnVyIERpb3hpZGUgdnMgRnJlZSBTdWxmdXIgRGlveGlkZQpgYGB7cn0KcGxvdF9iaV92YXIoJ2ZyZWUuc3VsZnVyLmRpb3hpZGUnLCAndG90YWwuc3VsZnVyLmRpb3hpZGUnKSArIGdlb21fYWJsaW5lKHNsb3BlPTEpCmNvcih3aW5lX3JlZHMkZnJlZS5zdWxmdXIuZGlveGlkZSwgd2luZV9yZWRzJHRvdGFsLnN1bGZ1ci5kaW94aWRlKQpgYGAKClRvdGFsIHN1bGZ1ciBkaW94aWRlIGFuZCBmcmVlIHN1bGZ1ciBkaW94aWRlIGhhdmUgYSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAwLjY2NzY2NjUuIFRoaXMgaXMgYmVjYXVzZSBmcmVlIHN1bGZ1ciBkaW94aWRlIGlzIHBhcnQgb2YgdG90YWwgc3VsZnVyIGRpb3hpZGUsIGFuZCB0aGlzIGNhbiBhbHNvIGJlIHNlZW4gZnJvbSBhbGwgdGhlIHBvaW50cyBhcmUgYWJvdmUgdGhlIHk9eCBsaW5lLgoKIyMgRGVuc2l0eSB2cyBBbGNvaG9sCmBgYHtyfQpwbG90X2JpX3ZhcignYWxjb2hvbCcsICdkZW5zaXR5JykKY29yKHdpbmVfcmVkcyRhbGNvaG9sLCB3aW5lX3JlZHMkZGVuc2l0eSkKYGBgCgpEZW5zaXR5IGFuZCBhbGNvaG9sIGhhdmUgYSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAtMC40OTYxNzk4LiBUaGlzIGlzIHByb2JhYmx5IGJlY2F1c2UgYWxjb2hvbCBoYXMgYSBsb3dlciBkZW5zaXR5IGNvbXBhcmluZyB0byB3YXRlci4gVGhlcmVmb3JlLCB0aGUgaGlnaGVyIGNvbmNlbnRyYXRpb24gb2YgYWxjb2hvbCwgdGhlIGxvd2VyIHRoZSB3aW5lIGRlbnNpdHkgaXMuCgojIyBEZW5zaXR5IHZzIEZpeGVkIEFjaWRpdHkKYGBge3J9CnBsb3RfYmlfdmFyKCdmaXhlZC5hY2lkaXR5JywgJ2RlbnNpdHknKQpjb3Iod2luZV9yZWRzJGZpeGVkLmFjaWRpdHksIHdpbmVfcmVkcyRkZW5zaXR5KQpgYGAKCkRlbnNpZHkgYW5kIGZpeGVkIGFjaWRpdHkgaGF2ZSBhIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIDAuNjY4MDQ3My4gVGhpcyBpcyBwcm9iYWJseSBiZWNhdXNlIGZpeGVkIGFjaWRpdHkgaW4gd2luZSBpcyBtYWlubHkgdGFydGFyaWMgYWNpZCwgYW5kIHRhcnRhcmljIGFjaWQgaGFzIGEgZGVuc2l0eSBvZiAxLjc5IGcvbUwsIHdoaWNoIGlzIGdyZWF0ZXIgdGhhbiB0aGUgd2luZSdzIG1haW4gY29tcG9uZW50LS13YXRlci4gVGhlcmVmb3JlLCBoaWdoZXIgY29uY2VudHJhdGlvbiBvZiBmaXhlZCBhY2lkaXR5IGxlYWRzIHRvIGhpZ2hlciBkZW5zaXR5IHZhbHVlLgoKIyBCaXZhcmlhdGUgQW5hbHlzaXMKCioqVGFsayBhYm91dCBzb21lIG9mIHRoZSByZWxhdGlvbnNoaXBzIHlvdSBvYnNlcnZlZCBpbiB0aGlzIHBhcnQgb2YgdGhlIGludmVzdGlnYXRpb24uIEhvdyBkaWQgdGhlIGZlYXR1cmUocykgb2YgaW50ZXJlc3QgdmFyeSB3aXRoIG90aGVyIGZlYXR1cmVzIGluIHRoZSBkYXRhc2V0PyoqCgpUaGVyZSBhcmUgYSBmZXcgYXR0cmlidXRlcyBleGhpYml0IHNvbWUgdHJlbmRzIHRoYXQgbG9vayBwcm9taXNpbmcgdG8gYmUgdXNlZCB0byBwcmVkaWN0IHF1YWxpdHkuIAoKKiBRdWFsaXR5IGlzIHBvc2l0aXZlbHkgY29ycmVsYXRlZCB3aXRoIGNpdHJpYyBhY2lkLCBzdWxwaGF0ZXMsIGFuZCBhbGNvaG9sLgoqIFF1YWxpdHkgaW5jcmVhc2VzIGlzIG5lZ2F0aXZlbHkgY29ycmVsYXRlZCB3aXRoIHZvbGF0aWxlIGFjaWRpdHksIGNobG9yaWRlcywgZGVuc2l0eSwgYW5kIHBILgoKV2UgY2FuIHN1bW1hcml6ZSB0aGVzZSByZWxhdGlvbnMgaW4gdGhlIGZvbGxvd2luZyB0YWJsZToKCnwgQXR0cmlidXRlIE5hbWUgICAgICAgfCBSZWxhdGlvbiB3aXRoIFF1YWxpdHkgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCBmaXhlZCBhY2lkaXR5ICAgICAgICB8ICAgICAgICAgICB+ICAgICAgICAgICB8Cnwgdm9sYXRpbGUgYWNpZGl0eSAgICAgfCAgICAgICAgICAgLSAgICAgICAgICAgfAp8IGNpdHJpYyBhY2lkICAgICAgICAgIHwgICAgICAgICAgICsgICAgICAgICAgIHwKfCByZXNpZHVhbCBzdWdhciAgICAgICB8ICAgICAgICAgICB+ICAgICAgICAgICB8CnwgY2hsb3JpZGVzICAgICAgICAgICAgfCAgICAgICAgICAgLSAgICAgICAgICAgfAp8IGZyZWUgc3VsZnVyIGRpb3hpZGUgIHwgICAgICAgICAgIH4gICAgICAgICAgIHwKfCB0b3RhbCBzdWxmdXIgZGlveGlkZSB8ICAgICAgICAgICB+ICAgICAgICAgICB8CnwgZGVuc2l0eSAgICAgICAgICAgICAgfCAgICAgICAgICAgLSAgICAgICAgICAgfAp8IHBIICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgIC0gICAgICAgICAgIHwKfCBzdWxwaGF0ZXMgICAgICAgICAgICB8ICAgICAgICAgICArICAgICAgICAgICB8CnwgYWxjb2hvbCAgICAgICAgICAgICAgfCAgICAgICAgICAgKyAgICAgICAgICAgfAoKKiAnficgbWVhbnMgdGhlIGF0dHJpYnV0ZSBleGhpYml0cyBubyBjbGVhciB0cmVuZCB3aXRoIHF1YWxpdHkKKiAnLScgbWVhbnMgdGhlIGF0dHJpYnV0ZSBpcyBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCBxdWFsaXR5CiogJysnIG1lYW5zIHRoZSBhdHRyaWJ1dGUgaXMgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHdpdGggcXVhbGl0eQoKKipEaWQgeW91IG9ic2VydmUgYW55IGludGVyZXN0aW5nIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGUgb3RoZXIgZmVhdHVyZXMgKG5vdCB0aGUgbWFpbiBmZWF0dXJlKHMpIG9mIGludGVyZXN0KT8qKgoKVGhlcmUgYXJlIGEgZmV3IGF0dHJpYnV0ZXMgdGhhdCBhcmUgY29ycmVsYXRlZCBiYXNlZCBvbiBwaHlzaWNhbCBhbmQgY2hlbWljYWwgcHJpbmNpcGxlczoKCiogRml4ZWQgYWNpZGl0eSBhbmQgY2l0cmljIGFjaWQgYXJlIHBvc2l0aXZlbHkgY29ycmVsYXRlZCBiZWNhdXNlIHRoZSBmaXhlZCBhY2lkaXR5IGluY2x1ZGVzIGNpdHJpYyBhY2lkLgoqIFRvdGFsIHN1bGZ1ciBkaW94aWRlIGFuZCBmcmVlIHN1bGZ1ciBkaW94aWRlIGFyZSBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgYmVjYXVzZSB0b3RhbCBzdWxmdXIgZGlveGlkZSBpbmNsdWRlcyBmcmVlIHN1bGZ1ciBkaW94aWRlLgoqIEZpeGVkIGFjaWRpdHkgYW5kIHBIIGFyZSBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgYmVjYXVzZSBoaWdoZXIgY29uY2VudHJhdGlvbiBvZiBmaXhlZCBhY2lkaXR5IG1ha2VzIHRoZSB3aW5lIG1vcmUgYWNpZGljLCB0aGVyZWZvcmUgdGhlIHdpbmUgaGFzIGEgbG93ZXIgcEguCiogQ2l0cmljIGFjaWQgYW5kIHBIIGFyZSBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgYmVjYXVzZSBoaWdoZXIgY29uY2VudHJhdGlvbiBvZiBjaXRyaWMgYWNpZCwgd2hpY2ggaXMgbm9uLXZvbGF0aWxlLCBtYWtlcyB0aGUgd2luZSBtb3JlIGFjaWRpYywgdGhlcmVmb3JlIHRoZSB3aW5lIGhhcyBhIGxvd2VyIHBILgoqIERlbnNpdHkgYW5kIGFsY29ob2wgYXJlIG5lZ2F0aXZlbHkgY29ycmVsYXRlZCBiZWNhdXNlIGFsY29ob2wgaGFzIGEgbG93ZXIgZGVuc2l0eSB0aGFuIHdhdGVyLCB0aGVyZWZvcmUgd2luZXMgdGhhdCBjb250YWluIG1vcmUgYWxjb2hvbCBoYXZlIGEgbG93ZXIgZGVuc2l0eS4KKiBEZW5zaXR5IGFuZCBmaXhlZCBhY2lkaXR5IGFyZSBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgYmVjYXVzZSB0aGUgbWFpbiBmaXhlZCBhY2lkcyBpbiB3aW5lLCB0YXJ0YXJpYyBhY2lkLCBoYXMgYSBoaWdoZXIgZGVuc2l0eSB0aGFuIHdhdGVyLCB0aGVyZWZvcmUgd2luZXMgdGhhdCBjb250YWluIG1vcmUgdGFydGFyaWMgYWNpZCBoYXZlIGEgaGlnaGVyIGRlbnNpdHkuIAoKKipXaGF0IHdhcyB0aGUgc3Ryb25nZXN0IHJlbGF0aW9uc2hpcCB5b3UgZm91bmQ/KioKCk9ic2VydmluZyBmcm9tIHRoZSBwbG90LCB2b2xhdGlsZSBhY2lkaXR5IGhhcyB0aGUgc3Ryb25nZXN0IHJlbGF0aW9uc2hpcCB3aXRoIHF1YWxpdHkuCgojIE11bHRpdmFyaWF0ZSBFeHBsb3JhdGlvbiBQYXJ0IEkKCkluIHRoaXMgc2VjdGlvbiwgSSB3aWxsIGZpcnN0IGxvb2sgYXQgaG93IHF1YWxpdHksIHZvbGF0aWxlIGFjaWRpdHkgYW5kIG9uZSBvdGhlciBpbnB1dCB2YXJpYWJsZSBhcmUgcmVsYXRlZC4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHBsb3Qgc2NhdHRlciBwbG90IG9mIHZhcmlhYmxlMiB2cyB2YXJpYWJsZTEgY29sb3JlZCBieSBxdWFsaXR5CnBsb3RfcXVhbGl0eV92c190d29fdmFyIDwtIGZ1bmN0aW9uKHZhcmlhYmxlMSwgdmFyaWFibGUyKSB7CiAgZ2dwbG90KGFlc19zdHJpbmcoeCA9IHZhcmlhYmxlMSwgeSA9IHZhcmlhYmxlMiwgY29sb3IgPSAncXVhbGl0eScpLCBkYXRhID0gd2luZV9yZWRzKSArCiAgICBnZW9tX2ppdHRlcihhbHBoYSA9IDEvMikgKwogICAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAnZGl2JykKfQpgYGAKCiMjIFF1YWxpdHkgdnMgVm9sYXRpbGUgQWNpZGl0eSBhbmQgQ2l0cmljIEFjaWQKYGBge3J9CnBsb3RfcXVhbGl0eV92c190d29fdmFyKCd2b2xhdGlsZS5hY2lkaXR5JywgJ2NpdHJpYy5hY2lkJykKYGBgCgpIaWdoIHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBoaWdoIGNpdHJpYyBhY2lkICh1cHBlciBsZWZ0IGNvcm5lcik7IGxvdyBxdWFsaXR5IHdpbmVzIHRlbmQgdG8gaGF2ZSBoaWdoIHZvbGF0aWxlIGFjaWRpdHkgYW5kIGxvdyBjaXRyaWMgYWNpZCAoIGxvd2VyIHJpZ2h0IGNvcm5lcikuCgojIyBRdWFsaXR5IHZzIFZvbGF0aWxlIEFjaWRpdHkgYW5kIFN1bHBoYXRlcwpgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3R3b192YXIoJ3N1bHBoYXRlcycsICd2b2xhdGlsZS5hY2lkaXR5JykKYGBgCgpIaWdoIHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBoaWdoIHN1bHBoYXRlcyAobG93ZXIgcmlnaHQgY29ybmVyKTsgbG93IHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGhpZ2ggdm9sYXRpbGUgYWNpZGl0eSBhbmQgbG93IHN1bHBoYXRlcyAodXBwZXIgbGVmdCBjb3JuZXIpLgoKIyMgUXVhbGl0eSB2cyBWb2xhdGlsZSBBY2lkaXR5IGFuZCBBbGNvaG9sCmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdHdvX3ZhcignYWxjb2hvbCcsICd2b2xhdGlsZS5hY2lkaXR5JykKYGBgCgpIaWdoIHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBoaWdoIGFsY29ob2wgKGxvd2VyIHJpZ2h0IGNvcm5lcik7IGxvdyBxdWFsaXR5IHdpbmVzIHRlbmQgdG8gaGF2ZSBoaWdoIHZvbGF0aWxlIGFjaWRpdHkgYW5kIGxvdyBhbGNvaG9sICh1cHBlciBsZWZ0IGNvcm5lcikuCgojIyBRdWFsaXR5IHZzIFZvbGF0aWxlIEFjaWRpdHkgYW5kIENobG9yaWRlcwpgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3R3b192YXIoJ2NobG9yaWRlcycsICd2b2xhdGlsZS5hY2lkaXR5JykgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjIpKQpgYGAKCkhpZ2ggcXVhbGl0eSB3aW5lcyB0ZW5kIHRvIGhhdmUgbG93IHZvbGF0aWxlIGFjaWRpdHkgYW5kIGxvdyBjaGxvcmlkZXMgKGxvd2VyIGxlZnQgY29ybmVyKTsgbG93IHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGhpZ2ggdm9sYXRpbGUgYWNpZGl0eSBhbmQgaGlnaCBjaGxvcmlkZXMgKHVwcGVyIHJpZ2h0IGNvcm5lcikuCgojIyBRdWFsaXR5IHZzIFZvbGF0aWxlIEFjaWRpdHkgYW5kIERlbnNpdHkKYGBge3J9CnBsb3RfcXVhbGl0eV92c190d29fdmFyKCdkZW5zaXR5JywgJ3ZvbGF0aWxlLmFjaWRpdHknKQpgYGAKCkhpZ2ggcXVhbGl0eSB3aW5lcyB0ZW5kIHRvIGhhdmUgbG93IHZvbGF0aWxlIGFjaWRpdHkgYW5kIGxvdyBkZW5zaXR5IChsb3dlciBsZWZ0IGNvcm5lcik7IGxvdyBxdWFsaXR5IHdpbmVzIHRlbmQgdG8gaGF2ZSBoaWdoIHZvbGF0aWxlIGFjaWRpdHkgYW5kIGhpZ2ggZGVuc2l0eSAodXBwZXIgcmlnaHQgY29ybmVyKS4KCiMjIFF1YWxpdHkgdnMgVm9sYXRpbGUgQWNpZGl0eSBhbmQgcEgKYGBge3J9CnBsb3RfcXVhbGl0eV92c190d29fdmFyKCdwSCcsICd2b2xhdGlsZS5hY2lkaXR5JykKYGBgCgpIaWdoIHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBsb3cgcEggKGxvd2VyIGxlZnQgY29ybmVyKTsgbG93IHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGhpZ2ggdm9sYXRpbGUgYWNpZGl0eSBhbmQgaGlnaCBwSCAodXBwZXIgcmlnaHQgY29ybmVyKS4KCiMgTXVsdGl2YXJpYXRlIEV4cGxvcmF0aW9uIFBhcnQgSUkKCkluIHRoaXMgc2VjdGlvbiwgSSB3aWxsIGV4YW1pbmUgdGhlIHJlbGF0aW9uIGFtb25nIHNvbWUgb2YgaW5wdXQgdmFyaWFibGUgdHJpcGxldHMuCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGN1dCBnaXZlbiBjb2x1bW4gZnJvbSB3aW5lX3JlZHMgZGF0YSBzZXQgaW50byBxdWFydGlsZXMKY3V0X3F1YXJ0aWxlcyA8LSBmdW5jdGlvbih2YXJfdG9fY3V0KSB7CiAgcmV0dXJuIChjdXQod2luZV9yZWRzW1t2YXJfdG9fY3V0XV0sIAogICAgICAgICAgICAgIGJyZWFrcyA9IHF1YW50aWxlKHdpbmVfcmVkc1tbdmFyX3RvX2N1dF1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icyA9IHNlcSgwLCAxLCAwLjI1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkpCn0KYGBgCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBwbG90IHNjYXR0ZXIgcGxvdCBvZiB2YXJpYWJsZTIgdnMgdmFyaWFibGUxIGNvbG9yZWQgYnkgdmFyaWFibGUzCnBsb3RfdHJpX3ZhciA8LSBmdW5jdGlvbih2YXJpYWJsZTEsIHZhcmlhYmxlMiwgdmFyaWFibGUzKXsKICBnZ3Bsb3QoYWVzX3N0cmluZyh4ID0gdmFyaWFibGUxLCB5ID0gdmFyaWFibGUyLCBjb2xvciA9IHZhcmlhYmxlMyksCiAgICAgICAgIGRhdGEgPSB3aW5lX3JlZHMpICsgCiAgICBnZW9tX2ppdHRlcigpICsgCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICdzZXEnKSArIAogICAgdGhlbWVfZGFyaygpCn0KYGBgCgojIyBwSCB2cyBGaXhlZCBBY2lkaXR5IGFuZCBDaXRyaWMgQWNpZApgYGB7cn0Kd2luZV9yZWRzJHBIX3F1YXJ0aWxlcyA8LSBjdXRfcXVhcnRpbGVzKCdwSCcpCnBsb3RfdHJpX3ZhcignY2l0cmljLmFjaWQnLCAnZml4ZWQuYWNpZGl0eScsICdwSF9xdWFydGlsZXMnKQpgYGAKCkZpeGVkIGFjaWRpdHkgYW5kIGNpdHJpYyBhY2lkIGJvdGggY29udHJpYnV0ZSB0byB3aW5lcycgcEggdmFsdWVzLiBUaGUgbG93ZXIgYm90aCBhY2lkcyBjb25jZW50cmF0aW9ucywgdGhlIGhpZ2hlciB0aGUgcEggKGxvd2VyIGxlZnQgY29ybmVyKSwgYW5kIHRoZSBoaWdoZXIgYm90aCBhY2lkZXMgY29uY2VudHJhdGlvbnMsIHRoZSBsb3dlciB0aGUgcEggKHVwcGVyIHJpZ2h0IGNvcm5lcikuCgojIyBEZW5zaXR5IHZzIEFsY29ob2wgYW5kIEZpeGVkIEFjaWRpdHkKYGBge3J9CndpbmVfcmVkcyRkZW5zaXR5X3F1YXJ0aWxlcyA8LSBjdXRfcXVhcnRpbGVzKCdkZW5zaXR5JykKcGxvdF90cmlfdmFyKCdhbGNvaG9sJywgJ2ZpeGVkLmFjaWRpdHknLCAnZGVuc2l0eV9xdWFydGlsZXMnKQpgYGAKCkZpeGVkIGFjaWRpdHkgaXMgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHdpdGggZGVuc2l0eSwgYW5kIGFsY29ob2wgaXMgbmVnYXRpdmVseSBjb3JyZWxhdGVkIHdpdGggZGVuc2l0eS4gV2UgY2FuIHNlZSBmcm9tIHRoZSBwbG90IHRoYXQgZml4ZWQgYWNpZGl0eSBoYXMgYSBsYXJnZXIgaW1wYWN0IG9uIHRoZSBkZW5zaXR5IG9mIHdpbmUgdGhhbiBhbGNvaG9sLiBCZWNhdXNlIGZvciBhIGdpdmVuIGFsY29ob2wgdmFsdWUsIHRoZSBkZW5zaXR5IGluY3JlYXNlcyBhcyBmaXhlZCBhY2lkaXR5IGluY3JlYXNlcywgd2hlcmVhcyBmb3IgYSBnaXZlbiBmaXhlZCBhY2lkaXR5IHZhbHVlLCB0aGUgZGVuc2l0eSBkb2VzIG5vdCBjaGFuZ2UgYXMgdGhlIGFsY29ob2wgaW5jcmVhc2VzLgoKIyBMaW5lYXIgTW9kZWxzCgpJbiBvcmRlciB0byBmaXQgYSBsaW5lYXIgbW9kZWwsIEkgd2lsbCBjb252ZXJ0IHF1YWxpdHkgZnJvbSBvcmRlcmVkIGZhY3RvcnMgYmFjayBpbnRvIHJlYWwgbnVtYmVycy4gCgoqIEZpcnN0IG1vZGVsIEkgd2lsbCBvbmx5IGxvb2sgYXQgdGhlIG1vc3QgcHJvbWlzaW5nIGF0dHJpYnV0ZSB2b2xhdGlsZSBhY2lkaXR5IGZyb20gdW5pdmFyaWF0ZSBleHBsb3JhdGlvbiBzZWN0aW9uLiAKKiBTZWNvbmRlIG1vZGVsIEkgd2lsbCBhZGQgdGhlIGF0dHJpYnV0ZXMgdGhhdCBleGhpYml0IGEgY2xlYXIgdHJlbmQgd2l0aCBxdWFsaXR5IGZyb20gdGhlIGJpdmFyaWF0ZSBleHBsb3JhdGlvbiBzZWN0aW9uIGJlc2lkZXMgdm9sYXRpbGUgYWNpZGl0eS4gCiogVGhpcmQgbW9kZWwgSSB3aWxsIGFkZCBhbGwgdGhlIHJlc3QgdmFyaWFibGVzLgoKYGBge3J9Cm0xIDwtICBsbShhcy5udW1lcmljKGxldmVscyhxdWFsaXR5KSlbcXVhbGl0eV0gfiB2b2xhdGlsZS5hY2lkaXR5LCAKICAgICAgICAgIGRhdGEgPSB3aW5lX3JlZHMpCm0yIDwtIHVwZGF0ZShtMSwgfiAuICsgdm9sYXRpbGUuYWNpZGl0eSArIGNpdHJpYy5hY2lkICsgc3VscGhhdGVzICsgYWxjb2hvbCArIAogICAgICAgICAgICAgICBjaGxvcmlkZXMgKyBkZW5zaXR5ICsgcEgpCm0zIDwtIHVwZGF0ZShtMiwgfiAuICsgZml4ZWQuYWNpZGl0eSArIHJlc2lkdWFsLnN1Z2FyICsgZnJlZS5zdWxmdXIuZGlveGlkZSArIAogICAgICAgICAgICAgICB0b3RhbC5zdWxmdXIuZGlveGlkZSkKbXRhYmxlKG0xLCBtMiwgbTMsIHNkaWdpdHMgPSAzKQpgYGAKCkFzIG9uZSBjYW4gc2VlLCB0aGUgbW9zdCBwcm9taXNpbmcgYXR0cmlidXRlIHZvbGF0aWxlIGFjaWRpY3kgYWxvbmUgaGFzIFItc3F1YXJlZCB2YWx1ZSBvZiAwLjE1My4gQnkgYWRkaW5nIHRoZSBvdGhlciA2IHByb21zaW5nIGF0dHJpYnV0ZXMsIFItc3F1YXJlZCB2YWx1ZSBpcyBhIGxpdHRsZSBtb3JlIHRoYW4gZG91YmxlZCBiZWNvbWluZyAwLjM1MC4gQnV0IGFkZGluZyB0aGUgcmVzdCA0IGF0dHJpYnV0ZXMgb25seSBpbmNyZWFzZXMgdGhlIFItc3F1YXJlZCB2YWx1ZSBhIGxpdHRsZSB0byAwLjM2MS4KCiMgTXVsdGl2YXJpYXRlIEFuYWx5c2lzCgoqKlRhbGsgYWJvdXQgc29tZSBvZiB0aGUgcmVsYXRpb25zaGlwcyB5b3Ugb2JzZXJ2ZWQgaW4gdGhpcyBwYXJ0IG9mIHRoZSBpbnZlc3RpZ2F0aW9uLiBXZXJlIHRoZXJlIGZlYXR1cmVzIHRoYXQgc3RyZW5ndGhlbmVkIGVhY2ggb3RoZXIgaW4gdGVybXMgb2YgbG9va2luZyBhdCB5b3VyIGZlYXR1cmUocykgb2YgaW50ZXJlc3Q/KioKCkJ5IGNvbWJpbmluZyB0aGUgbW9zdCBwcm9taXNpbmcgYXR0cmlidXRlIGZyb20gYml2YXJpYXRlIHNlY3Rpb24sIHZvbGF0aWxlIGFjaWRpdHksIHdpdGggb25lIG9mIHRoZSBvdGhlciBhdHRyaWJ1dGVzIChjaXRyaWMgYWNpZCwgc3VscGhhdGVzLCBhbGNvaG9sLCBjaGxvcmlkZXMsIGRlbnNpdHkgYW5kIHBIKSwgb25lIGNhbiBmdXJ0aGVyIHNlcGFyYXRlIGhpZ2ggcXVhbGl0eSB3aW5lcyBhbmQgbG93IHF1YWxpdHkgd2luZXMuCgoqKldlcmUgdGhlcmUgYW55IGludGVyZXN0aW5nIG9yIHN1cnByaXNpbmcgaW50ZXJhY3Rpb25zIGJldHdlZW4gZmVhdHVyZXM/KioKCkJ5IGxvb2tpbmcgYXQgZGVuc2l0eSB2cyBmaXhlZCBhY2lkaXR5IGFuZCBhbGNvaG9sLCBvbmUgY2FuIHNlZSB0aGF0IGZpeGVkIGFjaWRpdHkgaGFzIGEgbGFyZ2VyIGltcGFjdCBvbiB0aGUgZGVuc2l0eSBvZiB0aGUgd2luZSB0aGFuIGFsY29ob2wuCgoqKk9QVElPTkFMOiBEaWQgeW91IGNyZWF0ZSBhbnkgbW9kZWxzIHdpdGggeW91ciBkYXRhc2V0PyBEaXNjdXNzIHRoZSBzdHJlbmd0aHMgYW5kIGxpbWl0YXRpb25zIG9mIHlvdXIgbW9kZWwuKioKCkkgY3JlYXRlZCB0aHJlZSBsaW5lYXIgbW9kZWxzIHRvIHByZWRpY3QgdGhlIG91dHB1dCBhdHRyaWJ1dGUgcXVhbGl0eS4gVGhlIHN0cmVuZ3RoIG9mIHRoZSBtb2RlbCBpcyB0aGF0IGl0IGlzIGEgc2ltcGxlIGxpbmVhciBtb2RlbCBhbmQgaXQgaXMgZWFzeSB0byBpbnRlcnByZXQuIEhvd2V2ZXIsIGJlY2F1c2UgdGhlIHF1YWxpdHkgdmFsdWVzIGFyZSBkaXNjcmV0ZSBpbnRlZ2VyIHZhbHVlcywgdGhlIG1vZGVsIGlzIGxlc3MgYWNjdXJhdGUgY29tcGFyaW5nIHRvIGEgbW9yZSBudWFuY2VkIGNvbnRpbnVvdXMgcXVhbGl0eSB2YWx1ZSBtb2RlbC4gQWxzbyBkdWUgdG8gdGhlIGxpbWl0YXRpb24gb2YgdGhlIGRhdGFzZXQsIG9ubHkgcGh5c2ljYWwgYW5kIGNoZW1pY2FsIGF0dHJpYnV0ZXMgYXJlIGF2YWlsYWJsZSwgYW5kIG90aGVyIGltcG9ydCBhdHRyaWJ1dGVzLCBzdWNoIGFzIHByaWNlLCBjb2xvciwgc21lbGwsIGV0YyBhcmUgbWlzc2luZy4gVGhlIG90aGVyIGF0dHJpYnV0ZXMgbWF5IGluZmx1ZW5jZSB0aGUgcXVhbGl0eSB2YWx1ZXMgdG8gYSBsYXJnZSBleHRlbnQuCgojIEZpbmFsIFBsb3RzCiMjIFBsb3QgSQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KZ2dwbG90KGFlcyh4ID0gcXVhbGl0eSksIGRhdGEgPSB3aW5lX3JlZHMpICsgCiAgZ2VvbV9iYXIoYWVzKHkgPSAoLi5jb3VudC4uKS9zdW0oLi5jb3VudC4uKSkpICsKICBnZW9tX3RleHQoYWVzKHkgPSAoKC4uY291bnQuLikvc3VtKC4uY291bnQuLikpLCAKICAgICAgICAgICAgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQoKC4uY291bnQuLikvc3VtKC4uY291bnQuLikpKSwgCiAgICAgICAgICAgIHN0YXQgPSAiY291bnQiLCAKICAgICAgICAgICAgdmp1c3QgPSAtMC4yNSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsgCiAgeGxhYignUXVhbGl0eScpICsgCiAgeWxhYignUGVyY2VudCcpICsgCiAgZ2d0aXRsZSgnUXVhbGl0eSBSZWxhdGl2ZSBGcmVxdWVuY3kgSGlzdG9ncmFtJykgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpUaGUgcG9zc2libGUgcXVhbGl0eSB2YWx1ZXMgYXJlIHJhbmdpbmcgZnJvbSAwIHRvIDEwLCBob3dldmVyLCBhbGwgcmVkIHdpbmVzIGluIHRoZSBkYXRhc2V0IGhhdmUgcXVhbGl0eSB2YWx1ZXMgYmV0d2VlbiAzIGFuZCA4LiBUaGVyZSBpcyBubyBhbnkgcmVhbGx5IGJhZCB3aW5lIHdpdGggcXVhbGl0eSBiZWxvdyAzIG9yIGFueSByZWFsbHkgZ29vZCB3aW5lIHdpdGggcXVhbGl0eSBhYm92ZSA4LiBBbHNvLCBtb3N0IG9mIHRoZSByZWQgd2luZXMgaGF2ZSBxdWFsaXR5IDUgb3IgNiwgd2hpY2ggbWFrZSB0aGUgZGF0YXNldCBub3Qgd2VsbCBiYWxhbmNlZC4gCgojIyBQbG90IElJCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpwbG90X3F1YWxpdHlfdnNfdHdvX3Zhcignc3VscGhhdGVzJywgJ3ZvbGF0aWxlLmFjaWRpdHknKSArIAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKG1pbih3aW5lX3JlZHMkc3VscGhhdGVzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVhbnRpbGUod2luZV9yZWRzJHN1bHBoYXRlcywgMC45OSkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMobWluKHdpbmVfcmVkcyR2b2xhdGlsZS5hY2lkaXR5KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVhbnRpbGUod2luZV9yZWRzJHZvbGF0aWxlLmFjaWRpdHksIDAuOTkpKSkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gJ2RpdicsIG5hbWUgPSAnUXVhbGl0eScpICsKICB4bGFiKGV4cHJlc3Npb24oU3VscGhhdGVzfihnfmRtXnstM30pKSkgKyAKICB5bGFiKGV4cHJlc3Npb24oVm9sYXRpbGV+QWNpZGl0eX4oZ35kbV57LTN9KSkpICsgCiAgZ2d0aXRsZSgnUXVhbGl0eSB2cyBWb2xhdGlsZSBBY2lkaXR5IGFuZCBTdWxwaGF0ZXMnKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkV4Y2x1ZGluZyB0aGUgdXBwZXIgMSUgb3V0bGllcnMsIG9uZSBjYW4gc2VlIGZyb20gdGhlIHBsb3QgdGhhdCBoaWdoZXIgcXVhbGl0eSB3aW5lcyAoZGFyayBncmVlbikgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBoaWdoIHN1bHBoYXRlcyAobG93ZXIgcmlnaHQgY29ybmVyKSwgd2hpbGUgbG93ZXIgcXVhbGl0eSB3aW5lcyAoZGFyayBicm93bikgdGVuZCB0byBoYXZlIGhpZ2ggdm9sYXRpbGUgYWNpZGl0eSBhbmQgbG93IHN1bHBoYXRlcyAodXBwZXIgbGVmdCBjb3JuZXIpLgoKIyMgUGxvdCBJSUkKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CndpbmVfcmVkcyRwSF9xdWFydGlsZXMgPC0gY3V0X3F1YXJ0aWxlcygnZGVuc2l0eScpCnBsb3RfdHJpX3ZhcignYWxjb2hvbCcsICdmaXhlZC5hY2lkaXR5JywgJ2RlbnNpdHlfcXVhcnRpbGVzJykgKwogIHhsYWIoZXhwcmVzc2lvbihBbGNvaG9sfignJScpKSkgKyAKICB5bGFiKGV4cHJlc3Npb24oRml4ZWR+QWNpZGl0eX4oZ35kbV57LTN9KSkpICsgCiAgZ2d0aXRsZSgnRGVuc2l0eSB2cyBGaXhlZCBBY2lkaXR5IGFuZCBBbGNvaG9sJykgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihuYW1lID0gZXhwcmVzc2lvbihEZW5zaXR5fihnfmNtXnstM30pKSwgdHlwZSA9ICdzZXEnKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKRml4ZWQgYWNpZGl0eSBpcyBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCBkZW5zaXR5LCBhbmQgYWxjb2hvbCBpcyBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCBkZW5zaXR5LiBUaGUgZml4ZWQgYWNpZGl0eSBoYXMgYSBsYXJnZXIgaW1wYWN0IG9uIHRoZSBkZW5zaXR5IG9mIHdpbmUgdGhhbiBhbGNvaG9sLiBCZWNhdXNlIGZvciBhIGdpdmVuIGFsY29ob2wgdmFsdWUsIHRoZSBkZW5zaXR5IGluY3JlYXNlcyAoZnJvbSBsaWdodCBibHVlIHRvIGRhcmsgYmx1ZSkgYXMgZml4ZWQgYWNpZGl0eSBpbmNyZWFzZXMsIHdoZXJlYXMgZm9yIGEgZ2l2ZW4gZml4ZWQgYWNpZGl0eSB2YWx1ZSwgdGhlIGRlbnNpdHkgZG9lcyBub3QgY2hhbmdlIG11Y2ggYXMgdGhlIGFsY29ob2wgaW5jcmVhc2VzLgoKIyBSZWZsZWN0aW9uCgpUaGUgcmVkIHdpbmUgZGF0YSBzZXQgaGFzIDExIGlucHV0IHBoeXNpY29jaGVtaWNhbCBhdHRyaWJ1dGVzIGFuZCAxIHF1YWxpdHkgb3V0cHV0IGF0dHJpYnV0ZS4gVGhyb3VnaG91dCB0aGUgYW5hbHlzaXMsIEkgZm9jdXNlZCBvbiBhbnN3ZXJpbmcgdHdvIHF1YXRpb25zOiAKCiogMS4gSG93IGFyZSBkaWZmZXJlbnQgaW5wdXQgcGh5c2ljb2NoZW1pY2FsIGF0dHJpYnV0ZXMgcmVsYXRlZCB0byB0aGUgcXVhbGl0eSBvdXRwdXQgYXR0cmlidXRlPyAKKiAyLiBBcmUgdGhlcmUgaW50ZXJlc3RpbmcgcmVsYXRpb25zIGFtb25nIGlucHV0IHBoeXNpY29jaGVtaWNhbCBhdHRyaWJ1dGVzPwoKSSByYW4gaW50byBkaWZmaWN1bHRpZXMgd2hlbiBhbnN3ZXJpbmcgcXVlc3Rpb24gMS4gVGhlcmUgd2VyZSBtYW55IGNvbWJpbmF0aW9ucyBvZiB0aGUgMTEgaW5wdXQgYXR0cmlidXRlcyBJIGNvdWxkIHBpY2sgdG8gcGxvdCBhZ2FpbnN0IHRoZSBxdWFsaXR5IGF0dHJpYnV0ZS4gQnV0IEkgZGlkIG5vdCBoYXZlIGdvb2QgY3JpdGVyaWEgdG8gZGV0ZXJtaW5lIHRoZSBvcmRlciBvZiBpbXBvcnRhbmNlIG9mIHRoZXNlIGF0dHJpYnV0ZXMuIEkgcmVsaWVkIG9uIHZpc3VhbGl6YXRpb24gYW5kIGNob3NlIHRoZSB2b2xhdGlsZSBhY2lkaWN5IGFzIHRoZSBtb3N0IHByb21pc2luZyBhdHRyaWJ1dGUgYW5kIHVzZWQgaXQgYXMgdGhlIGZpeGVkIGF0dHJpYnV0ZSBkdXJpbmcgbXVsdGl2YXJpYXRlIHBsb3Qgc2VjdGlvbi4KCkkgZGlkIG9ic2VydmUgc29tZSBnb29kIHJlc3VsdHMgd2hlbiBhbnN3ZXJpbmcgcXVlc3Rpb24gMi4gVGhlIHBsb3RzIHNob3dpbmcgYmV0d2VlbiBhbmQgYW1vbmcgZGlmZmVyZW50IGlucHV0IHBoeXNpY29jaGVtaWNhbCBhdHRyaWJ1dGVzIHdlcmUgaW4gYWNjb3JkYW5jZSB3aXRoIGFjdHVhbCBwaHlzaWNhbCBhbmQgY2hlbWljYWwgcHJvcGVydGllcyBhbmQgbGF3cywgc3VjaCBoaWdoIGFjaWQgY29uY2VudHJhdGlvbiBjb3JyZWxhdGVzIHdpdGggbG93IHBILCBhbmQgaGlnaCBhbGNvaG9sIHBlcmNlbnQgY29ycmVsYXRlcyB3aXRoIGxvdyBkZW5zaXR5LgoKSSBiZWxpZXZlIGJ5IGluY29ycG9yYXRpbmcgb3RoZXIgdHlwZXMgb2YgYXR0cmlidXRlcywgc3VjaCBhcyBwcmljZSwgY29sb3IgYW5kIHNtZWxsLCBJIGNhbiBidWlsZCBhIGJldHRlciBtb2RlbCB0byBwcmVkaWN0IHRoZSBxdWFsaXR5IG9mIHdpbmUgdGhhbiB1c2luZyBvbmx5IHBoeXNpY29jaGVtaWNhbCBhdHRyaWJ1dGVzLiBBbHNvLCBvbmUgbW9yZSBpbnRlcmVzdGluZyBwcm9qZWN0IGNhbiBiZSBjb21iaW5pbmcgdGhlIHJlZCB3aW5lIGRhdGEgc2V0IHdpdGggdGhlIHdoaXRlIHdpbmUgZGF0YSBzZXQsIGFuZCB0byBmaW5kIG91dCBpZiBhdHRyaWJ1dGVzIGNvcnJlbGF0ZSB0byBoaWdoIHF1YWxpdHkgcmVkIHdpbmVzIGFsc28gY29ycmVsYXRlIHRvIGhpZ2ggcXVhbGl0eSB3aGl0ZSB3aW5lcy4=